﻿using Common;
using MongoDB;
using MongoDB.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using Newtonsoft.Json.Linq;

namespace Quartz.Service
{
    public class ApiService :IApiService
    {
        private readonly IMongoDB _mongoDB;

        private object lockobj = new object();
        public ApiService(IMongoDB mongoDB)
        {
            _mongoDB = mongoDB;
        }

        /// <summary>
        /// 验证头缓存Key为Task_Auth的Guid
        /// </summary>
        private static Dictionary<string, KeyValuePair<string, string>> AuthTokens = new Dictionary<string, KeyValuePair<string, string>>();

        /// <summary>
        /// 执行任务，返回任务API的Response内容
        /// </summary>
        /// <param name="Task"></param>
        /// <param name="IsRetry">是否是重试的</param>
        /// <returns></returns>
        public async Task<string> ExecuteTask(Mongo_TaskManageModel Task,bool IsRetry=false)
        {
            KeyValuePair<string, string> AuthToken = new KeyValuePair<string, string>();
            if (Task.AuthType!="0")
            {
                lock (lockobj)
                {
                    AuthToken = GetTaskAuthToken(Task.AuthType).Result;
                }
            }
            //将验证头加入到请求头里，根据配置的AuthTokenField
            var Header = new Dictionary<string, string>();
            if (!AuthToken.Key.IsNullOrWhiteSpace() && !AuthToken.Value.IsNullOrWhiteSpace())
            {
                Header.Add(AuthToken.Key, AuthToken.Value);
            }
            //如果配置了请求头，也将任务的请求头添加进去
            if(!Task.Token.IsNullOrWhiteSpace())
            {
                var headerJson = Task.Token.ToObject<Dictionary<string, string>>();
                if(headerJson != null&& headerJson.Count>0)
                {
                    foreach (var item in headerJson)
                    {
                        Header.Add(item.Key, item.Value);
                    }
                }
            }
            var Response = await HttpTool.SendHttp(url: Task.TaskUrl,
                                                    Method: Task.Method,
                                                    BodyType: Task.BodyType,
                                                    Body: Task.RequestBody.ToObject<Dictionary<string, object>>(),
                                                    Header: Header);
            //如果是返回未验证,判断一下是否配有验证方式，如果没有配置，则直接抛出错误。有配置则删除缓存中的AuthToken，重新进行验证。
            //如果是重试的（也就是重新验证了还是发送错误),则直接抛出错误
            if (Response.StatusCode == HttpStatusCode.Unauthorized)
            {
                if (Task.AuthType == "0"|| IsRetry)
                {
                    Stream EXstreamIn = Response.GetResponseStream();
                    StreamReader EXreader = new StreamReader(EXstreamIn);
                    string EXresult = EXreader.ReadToEnd();
                    EXreader.Close();
                    EXstreamIn.Close();
                    Response.Close();
                    Response.Dispose();
                    throw new Exception($"此接口验证不通过，请检查验证配置.错误信息:[{EXresult}]");
                }
                Response.Close();
                Response.Dispose();
                RemoveAuthToken(Task.AuthType);
                return await ExecuteTask(Task, true);
            }
            //获取响应内容，并且返回
            Stream streamIn = Response.GetResponseStream();
            StreamReader reader = new StreamReader(streamIn);
            string result = reader.ReadToEnd();
            reader.Close();
            streamIn.Close();
            Response.Close();
            Response.Dispose();
            return result;
        }

        /// <summary>
        /// 删除验证头，如果修改了验证配置，则需要删除原来的验证头
        /// </summary>
        /// <param name="guid"></param>
        /// <returns></returns>
        public void RemoveAuthToken(string guid)
        {
            lock (lockobj)
            {
                if (AuthTokens.ContainsKey(guid))
                {
                    AuthTokens.Remove(guid);
                }
            }
        }

        /// <summary>
        /// 获取任务验证头
        /// </summary>
        /// <param name="Guid"></param>
        /// <returns></returns>
        private async Task<KeyValuePair<string, string>> GetTaskAuthToken(string Guid)
        {
            if (AuthTokens.ContainsKey(Guid))
            {
                return AuthTokens[Guid];
            }
            var auth = await _mongoDB.GetCollection<Mongo_TaskAuth>("Task_Auth").FindInfoAsync(m => m.AuthGuid == Guid);
            if(auth!=null)
            {
                var resquestBody = new Dictionary<string, object>();
                resquestBody.Add(auth.UserNameField, auth.UserName);
                resquestBody.Add(auth.PswField, auth.Psw);
                var authBody = auth.RequestBody.ToObject<Dictionary<string, object>>();
                if (authBody != null && authBody.Count > 0)
                {
                    foreach (var body in authBody)
                    {
                        resquestBody.Add(body.Key, body.Value);
                    }
                }
                var AuthResponse = await HttpTool.SendHttp(url: auth.AuthUrl,
                                                        Method: auth.Method,
                                                        BodyType: auth.BodyType,
                                                        Body: resquestBody,
                                                        Header: auth.Token.ToObject<Dictionary<string, string>>());
                //获取响应内容
                Stream streamIn = AuthResponse.GetResponseStream();
                StreamReader reader = new StreamReader(streamIn);
                string result = reader.ReadToEnd();
                reader.Close();
                streamIn.Close();
                AuthResponse.Close();
                AuthResponse.Dispose();
                JObject resultJson = JObject.Parse(result);
                string AuthToken = string.Empty;
                if (!auth.AuthTokenField.IsNullOrWhiteSpace())
                {
                    JToken tokenStr = resultJson;
                    //通过循环取出验证Token
                    foreach (var field in auth.AuthTokenField.Split(":"))
                    {
                        tokenStr = tokenStr[field];
                        if (tokenStr == null)
                        {
                            throw new Exception("验证头所在字段出现问题,请检查验证配置");
                        }
                    }
                    if (tokenStr != null)
                    {
                        AuthToken = tokenStr.Value<string>();
                    }
                }
                if (AuthTokens.ContainsKey(Guid))
                {
                    AuthTokens.Remove(Guid);
                }
                var res = new KeyValuePair<string, string>(auth.AuthTokenHeader, AuthToken);
                AuthTokens.Add(Guid, res);
                return res;
            }
            return new KeyValuePair<string, string>();
        }
    }
}
